//
// Created by Kan Zheng on 23/04/2017.
//

#include "Lexer.h"
#include "../Scanner.h"
#include "../token/Id.h"
#include "../token/Keywords.h"
#include "../token/Num.h"

Scanner scanner;

Token *Lexer::tokenize(FILE *fp) {
    if (readNext)
        current = scan(fp);

    if(current == EOF)
        return new Token(Tag::ENDF);

    if (current == ' ') {
        do {
            current = scan(fp);
        } while (current == ' ');
        readNext = false;
        Token *token = new Token(Tag::SPACE);
        return token;
    }

    if(current == '\n') {
        readNext = true;
        Token *token = new Token(Tag::EOL);
        return token;
    }

    if ((current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z') || current == '_') {//标识符或关键字
        string name = "";
        do {
            name.push_back(current);
            current = scan(fp);
        } while ((current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z') || current == '_'
                 || (current >= '0' && current <= '9'));
        readNext = false;
        if (isKeyword(name)) {
            Keywords *keyword = new Keywords(name);
            return keyword;
        } else {
            Id *id = new Id(name);
            return id;
        }
    }

    if (current >= '0' && current <= '9') {//数字常量
        int val = 0;
        if (current != '0') {//十进制
            do {
                val = val * 10 + current - '0';
                current = scan(fp);
            } while (current >= '0' && current <= '9');
            Num *num = new Num(val);
            return num;
        } else {
            current = scan(fp);
            if (current == 'x') {
                current = scan(fp);
                if ((current >= '0' && current <= '9') || (current >= 'a' || current <= 'f')) {
                    do {
                        val = val * 16 + current;
                        if (current >= '0' && current <= '9')
                            val -= 0;
                        else if (current >= 'a' && current <= 'f')
                            val += 10 - 'a';

                        current = scan(fp);
                    } while ((current >= '0' && current <= '9') || (current >= 'a' || current <= 'f'));
                } else {
                    Token *t = new Token(Tag::ERR);
                    return t;
                }
            }
        }
    }

    if (current == '=') {
        Token *token = new Token(Tag::EQU);
        readNext = true;
        return token;
    }

    if (current == '+') {
        Token *token = new Token(Tag::ADD);
        readNext = true;
        return token;
    }

    if (current == ';') {
        readNext = true;
        Token *token = new Token(Tag::SEMICON);
        return token;
    }
    return new Token(Tag::UNKNOWN);
}

bool Lexer::isKeyword(string s) {
    return s == "int" || s == "char" || s == "string";
}

char Lexer::scan(FILE *fp) {
    return scanner.scan(fp);
}

void Lexer::init() {
    readNext = true;
}
